#ifndef VECTOR3_CU
#define VECTOR3_CU

#include "Vector3.h"

__host__ __device__  Vector3& Vector3::normalize()
{
  const float vector_length = sqrt( data[0]*data[0] +
				     data[1]*data[1] +
				     data[2]*data[2] );

  if (vector_length > 0.0) //dividing by zero isn't cool
    {
      data[0] /= vector_length;
      data[1] /= vector_length;
      data[2] /= vector_length;
    }

  return *this;
}

__host__ __device__  float Vector3::dot(const Vector3& v) const
{
    return  data[0]*v.data[0]
           +data[1]*v.data[1]
           +data[2]*v.data[2];
}

__host__ __device__  Vector3 Vector3::cross(const Vector3& v) const
{
    float x,y,z;
      x = data[1]*v.data[2] - data[2]*v.data[1];
      y = data[2]*v.data[0] - data[0]*v.data[2];
      z = data[0]*v.data[1] - data[1]*v.data[0];
      return Vector3(x,y,z);
}

__host__ __device__  float Vector3::magnitude() const {
    return sqrt(data[0] * data[0] +
                data[1] * data[1] +
                data[2] * data[2]);
}

__host__ __device__  Vector3 Vector3::mix(const Vector3& v) const{
    Vector3 final = Vector3();
    final.data[0] = this->data[0]*v.data[0];
    final.data[1] = this->data[1]*v.data[1];
    final.data[2] = this->data[2]*v.data[2];
    return final;
}

__host__ __device__  Vector3 Vector3::weightedAverage(const Vector3& v, float weight) const {
    Vector3 final;
    float weightInv = 1.0f-weight;
    final.data[0] = this->data[0]*weightInv + v.data[0]*weight;
    final.data[1] = this->data[1]*weightInv + v.data[1]*weight;
    final.data[2] = this->data[2]*weightInv + v.data[2]*weight;
    return final;
}

__host__ __device__  Vector3& Vector3::cap(float value){
    data[0] = min(data[0], value);
    data[1] = min(data[1], value);
    data[2] = min(data[2], value);
    return *this;
}

__host__ __device__  Vector3 Vector3::bisect(const Vector3& v) const{
    Vector3 bisector(*this);
    bisector += v;
    bisector.normalize();
    return bisector;
}

  __host__ __device__  const Vector3 operator+(const Vector3 &lhs, const Vector3 &rhs)
  {
    return Vector3(lhs) += rhs;
  }
  __host__ __device__  const Vector3 operator-(const Vector3 &lhs, const Vector3 &rhs)
  {
    return Vector3(lhs) -= rhs;
  }
  __host__ __device__  const Vector3 operator+(const Vector3& lhs, const float rhs){
	return Vector3(lhs[0] + rhs, lhs[1] + rhs, lhs[2] + rhs);
  }

  __host__ __device__  const Vector3 operator-(const Vector3& lhs, const float rhs){
	return Vector3(lhs[0] - rhs, lhs[1] - rhs, lhs[2] - rhs);
  }

  __host__ __device__  const Vector3 operator*(const Vector3 &lhs, const float rhs)
  {
    return Vector3(lhs) *= rhs;
  }
  __host__ __device__  const Vector3 operator*(const float lhs, const Vector3 &rhs)
  {
    return Vector3(rhs) *= lhs;
  }
  __host__ __device__  const Vector3 operator/(const Vector3 &lhs, const float rhs)
  {
    return Vector3(lhs) /= rhs;
  }

__host__ __device__  bool operator<(const Vector3& lhs, const Vector3& rhs){
    return (lhs[0] < rhs[0] &&
            lhs[1] < rhs[1] &&
            lhs[2] < rhs[2]);
}
__host__ __device__  bool operator<=(const Vector3& lhs, const Vector3& rhs){
    return (lhs[0] <= rhs[0] &&
            lhs[1] <= rhs[1] &&
            lhs[2] <= rhs[2]);
    
}
__host__ __device__  bool operator>(const Vector3& lhs, const Vector3& rhs){
    return (lhs[0] > rhs[0] &&
            lhs[1] > rhs[1] &&
            lhs[2] > rhs[2]);
    
}
__host__ __device__  bool operator>=(const Vector3& lhs, const Vector3& rhs){
    return (lhs[0] >= rhs[0] &&
            lhs[1] >= rhs[1] &&
            lhs[2] >= rhs[2]);
}

#endif
